/*     */ package com.zimbra.cs.datasource.imap;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.net.SocketFactories;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.DataSource;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.datasource.MessageContent;
/*     */ import com.zimbra.cs.datasource.SyncUtil;
/*     */ import com.zimbra.cs.mailclient.CommandFailedException;
/*     */ import com.zimbra.cs.mailclient.MailConfig.Security;
/*     */ import com.zimbra.cs.mailclient.auth.Authenticator;
/*     */ import com.zimbra.cs.mailclient.auth.AuthenticatorFactory;
/*     */ import com.zimbra.cs.mailclient.imap.CAtom;
/*     */ import com.zimbra.cs.mailclient.imap.DataHandler;
/*     */ import com.zimbra.cs.mailclient.imap.IDInfo;
/*     */ import com.zimbra.cs.mailclient.imap.ImapConfig;
/*     */ import com.zimbra.cs.mailclient.imap.ImapConnection;
/*     */ import com.zimbra.cs.mailclient.imap.ImapData;
/*     */ import com.zimbra.cs.mailclient.imap.ImapResponse;
/*     */ import com.zimbra.cs.mailclient.imap.ResponseHandler;
/*     */ import com.zimbra.cs.util.BuildInfo;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import com.zimbra.soap.type.DataSource.ConnectionType;
/*     */ import java.io.IOException;
/*     */ import java.util.Collections;
/*     */ import java.util.HashMap;
/*     */ import java.util.Map;
/*     */ import javax.security.auth.login.LoginException;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ final class ConnectionManager
/*     */ {
/*  53 */   private Map<String, ImapConnection> connections = Collections.synchronizedMap(new HashMap());
/*     */   
/*     */ 
/*  56 */   private static final ConnectionManager INSTANCE = new ConnectionManager();
/*     */   
/*  58 */   private static final boolean REUSE_CONNECTIONS = LC.data_source_imap_reuse_connections.booleanValue();
/*     */   
/*     */ 
/*     */   private static final int IDLE_READ_TIMEOUT = 1800;
/*     */   
/*  63 */   private static final Log LOG = ZimbraLog.datasource;
/*     */   
/*     */   public static ConnectionManager getInstance() {
/*  66 */     return INSTANCE;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public ImapConnection openConnection(DataSource ds, Authenticator auth)
/*     */     throws ServiceException
/*     */   {
/*  85 */     ImapConnection ic = (ImapConnection)this.connections.remove(ds.getId());
/*  86 */     if ((ic == null) || (!resumeConnection(ic))) {
/*  87 */       ic = newConnection(ds, auth);
/*     */     }
/*  89 */     ic.getImapConfig().setMaxLiteralMemSize(ds.getMaxTraceSize());
/*  90 */     return ic;
/*     */   }
/*     */   
/*     */   public ImapConnection openConnection(DataSource ds) throws ServiceException {
/*  94 */     return openConnection(ds, null);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void releaseConnection(DataSource ds, ImapConnection ic)
/*     */   {
/* 106 */     LOG.debug("Releasing connection: " + ic);
/* 107 */     if ((isReuseConnections(ds)) && (suspendConnection(ds, ic))) {
/* 108 */       ImapConnection conn = (ImapConnection)this.connections.put(ds.getId(), ic);
/* 109 */       if (conn != null) {
/* 110 */         LOG.debug("More than one suspended connection for: %s. closing the oldest: %s", new Object[] { ds, conn });
/* 111 */         conn.close();
/*     */       }
/*     */     } else {
/* 114 */       LOG.debug("Closing connection: " + ic);
/* 115 */       ic.close();
/*     */     }
/*     */   }
/*     */   
/*     */   public void closeConnection(DataSource ds) {
/* 120 */     closeConnection(ds.getId());
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void closeConnection(String dataSourceId)
/*     */   {
/* 131 */     ImapConnection ic = (ImapConnection)this.connections.remove(dataSourceId);
/* 132 */     if (ic != null) {
/* 133 */       LOG.debug("Closing connection: " + ic);
/* 134 */       ic.close();
/*     */     }
/*     */   }
/*     */   
/*     */   private boolean isReuseConnections(DataSource ds) {
/* 139 */     return (ds.isOffline()) && (REUSE_CONNECTIONS);
/*     */   }
/*     */   
/*     */   private static ImapConnection newConnection(DataSource ds, Authenticator auth) throws ServiceException
/*     */   {
/* 144 */     ImapConfig config = newImapConfig(ds);
/* 145 */     ImapConnection ic = new ImapConnection(config);
/* 146 */     ic.setDataHandler(new FetchDataHandler(null));
/*     */     try {
/* 148 */       ic.connect();
/*     */       try {
/* 150 */         if (config.getMechanism() != null) {
/* 151 */           auth = AuthenticatorFactory.getDefault().newAuthenticator(config, ds.getDecryptedPassword());
/*     */         }
/* 153 */         if (auth == null) {
/* 154 */           ic.login(ds.getDecryptedPassword());
/*     */         } else {
/* 156 */           ic.authenticate(auth);
/*     */         }
/*     */       } catch (CommandFailedException e) {
/* 159 */         throw new LoginException(e.getError());
/*     */       }
/* 161 */       if (isImportingSelf(ds, ic)) {
/* 162 */         throw ServiceException.INVALID_REQUEST("User attempted to import messages from his/her own mailbox", null);
/*     */       }
/*     */     }
/*     */     catch (ServiceException e) {
/* 166 */       ic.close();
/* 167 */       throw e;
/*     */     } catch (Exception e) {
/* 169 */       ic.close();
/* 170 */       throw ServiceException.FAILURE("Unable to connect to IMAP server: " + ds, e);
/*     */     }
/*     */     
/* 173 */     LOG.debug("Created new connection: " + ic);
/* 174 */     return ic;
/*     */   }
/*     */   
/*     */   private static boolean isImportingSelf(DataSource ds, ImapConnection ic) throws IOException, ServiceException
/*     */   {
/* 179 */     if ((!ds.isOffline()) && (ic.hasCapability("ID"))) {
/*     */       try {
/* 181 */         IDInfo clientId = new IDInfo();
/* 182 */         clientId.put("name", IDInfo.DATASOURCE_IMAP_CLIENT_NAME);
/* 183 */         clientId.put("version", BuildInfo.VERSION);
/* 184 */         IDInfo id = ic.id(clientId);
/* 185 */         if ("Zimbra".equalsIgnoreCase(id.get("name"))) {
/* 186 */           String user = id.get("user");
/* 187 */           String server = id.get("server");
/* 188 */           return (user != null) && (user.equals(ds.getAccount().getName())) && (server != null) && (server.equals(Provisioning.getInstance().getLocalServer().getId()));
/*     */         }
/*     */       }
/*     */       catch (CommandFailedException e)
/*     */       {
/* 193 */         LOG.warn("ID command failed, assuming not importing self", e);
/*     */       }
/*     */     }
/* 196 */     return false;
/*     */   }
/*     */   
/*     */   private static class FetchDataHandler implements DataHandler
/*     */   {
/*     */     public Object handleData(ImapData data) throws Exception
/*     */     {
/*     */       try
/*     */       {
/* 205 */         return MessageContent.read(data.getInputStream(), data.getSize());
/*     */       } catch (OutOfMemoryError e) {
/* 207 */         Zimbra.halt("Out of memory", e); }
/* 208 */       return null;
/*     */     }
/*     */   }
/*     */   
/*     */   public static ImapConfig newImapConfig(DataSource ds)
/*     */   {
/* 214 */     ImapConfig config = new ImapConfig();
/* 215 */     config.setHost(ds.getHost());
/* 216 */     config.setPort(ds.getPort().intValue());
/* 217 */     config.setAuthenticationId(ds.getUsername());
/* 218 */     config.setSecurity(getSecurity(ds));
/* 219 */     config.setMechanism(ds.getAuthMechanism());
/* 220 */     config.setAuthorizationId(ds.getAuthId());
/*     */     
/*     */ 
/*     */ 
/*     */ 
/* 225 */     config.setUseLiteralPlus(false);
/*     */     
/* 227 */     if (ds.isDebugTraceEnabled()) {
/* 228 */       config.setLogger(SyncUtil.getTraceLogger(ZimbraLog.imap_client, ds.getId()));
/*     */     }
/* 230 */     config.setSocketFactory(SocketFactories.defaultSocketFactory());
/* 231 */     config.setSSLSocketFactory(SocketFactories.defaultSSLSocketFactory());
/* 232 */     config.setConnectTimeout(ds.getConnectTimeout(LC.javamail_imap_timeout.intValue()).intValue());
/* 233 */     config.setReadTimeout(ds.getReadTimeout(LC.javamail_imap_timeout.intValue()));
/* 234 */     LOG.debug("Connect timeout = %d, read timeout = %d", new Object[] { Integer.valueOf(config.getConnectTimeout()), Integer.valueOf(config.getReadTimeout()) });
/*     */     
/* 236 */     return config;
/*     */   }
/*     */   
/*     */   private static MailConfig.Security getSecurity(DataSource ds)
/*     */   {
/* 241 */     DataSource.ConnectionType type = ds.getConnectionType();
/* 242 */     if (type == null) {
/* 243 */       type = DataSource.ConnectionType.cleartext;
/*     */     }
/* 245 */     switch (type)
/*     */     {
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */     case cleartext: 
/* 252 */       return (!ds.isOffline()) && (LC.javamail_imap_enable_starttls.booleanValue()) ? MailConfig.Security.TLS_IF_AVAILABLE : MailConfig.Security.NONE;
/*     */     
/*     */     case ssl: 
/* 255 */       return MailConfig.Security.SSL;
/*     */     case tls: 
/* 257 */       return MailConfig.Security.TLS;
/*     */     case tls_if_available: 
/* 259 */       return MailConfig.Security.TLS_IF_AVAILABLE; }
/*     */     
/* 261 */     return MailConfig.Security.NONE;
/*     */   }
/*     */   
/*     */ 
/*     */   private static boolean suspendConnection(DataSource ds, ImapConnection ic)
/*     */   {
/* 267 */     if (ic.isClosed()) {
/* 268 */       return false;
/*     */     }
/*     */     try {
/* 271 */       if (ic.hasIdle()) {
/* 272 */         ic.setReadTimeout(1800);
/* 273 */         if (!ic.isSelected("INBOX")) {
/* 274 */           ic.select("INBOX");
/*     */         }
/* 276 */         ic.idle(idleHandler(ds));
/* 277 */       } else if (ic.isSelected()) {
/* 278 */         if (ic.hasUnselect()) {
/* 279 */           ic.unselect();
/*     */         } else {
/* 281 */           ic.close_mailbox();
/*     */         }
/*     */       }
/* 284 */       LOG.debug("Suspended connection: " + ic);
/*     */     } catch (IOException e) {
/* 286 */       LOG.warn("Error suspending connection", e);
/*     */     }
/* 288 */     return true;
/*     */   }
/*     */   
/*     */   private static ResponseHandler idleHandler(DataSource ds) {
/* 292 */     new ResponseHandler()
/*     */     {
/*     */       public void handleResponse(ImapResponse res) throws Exception {
/* 295 */         if (res.getCCode() == CAtom.EXISTS) {
/* 296 */           SyncState ss = SyncStateManager.getInstance().getOrCreateSyncState(this.val$ds);
/* 297 */           if (ss != null) {
/* 298 */             ss.setHasRemoteInboxChanges(true);
/*     */           }
/*     */         }
/*     */       }
/*     */     };
/*     */   }
/*     */   
/*     */   private static boolean resumeConnection(ImapConnection ic) {
/* 306 */     if (ic.isClosed()) {
/* 307 */       return false;
/*     */     }
/*     */     try {
/* 310 */       ic.setReadTimeout(ic.getImapConfig().getReadTimeout());
/* 311 */       if (ic.isIdling()) {
/* 312 */         if (!ic.stopIdle()) {
/* 313 */           return false;
/*     */         }
/*     */       } else {
/* 316 */         ic.noop();
/*     */       }
/* 318 */       LOG.debug("Resumed connection: " + ic);
/*     */     } catch (IOException e) {
/* 320 */       LOG.warn("Error resuming connection: " + ic, e);
/* 321 */       return false;
/*     */     }
/* 323 */     return true;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/datasource/imap/ConnectionManager.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */